package cn.tellfish.studydemo.mthread;

import lombok.extern.slf4j.Slf4j;

/**
 * 宇宙的能量系统
 * 遵循能量守恒定律：
 * 能量不会凭空创生或消失，只会从一处转移到另一处
 */
@Slf4j
public class EnergySystemFirst {

    //能量盒子，能量存贮的地方
    private final double[] energyBoxes;
//    private final Object lockObj = new Object();

    /**
     * @param n             能量盒子的数量
     * @param initialEnergy 每个能量盒子初始含有的能量值
     */
    public EnergySystemFirst(int n, double initialEnergy) {
        energyBoxes = new double[n];
        for (int i = 0; i < energyBoxes.length; i++)
            energyBoxes[i] = initialEnergy;
    }

    /**
     * 能量的转移，从一个盒子到另一个盒子
     *
     * @param from   能量源
     * @param to     能量终点
     * @param amount 能量值
     */
    public void transfer(int from, int to, double amount) {

//        synchronized (lockObj) {

//			 if (energyBoxes[from] < amount)
//				 return;
        //while循环，保证条件不满足时任务都会被条件阻挡
        //而不是继续竞争CPU资源
//            while (energyBoxes[from] < amount) {
//                try {
//                    //条件不满足, 将当前线程放入Wait Set
//                    lockObj.wait();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }


        System.out.print(Thread.currentThread().getName());

        energyBoxes[from] -= amount;
        System.out.printf("\t从%d转移\t%10.2f\t单位能量到\t%d", from, amount, to);
        energyBoxes[to] += amount;
        double ttl = getTotalEnergies();
        System.out.printf("\t能量总和：%10.2f%n", ttl);
        //唤醒所有在lockObj对象上等待的线程
//            lockObj.notifyAll();
//        }

    }

    /**
     * 获取能量世界的能量总和
     */
    public double getTotalEnergies() {
        double sum = 0;
        for (double amount : energyBoxes)
            sum += amount;
        return sum;
    }

    //将要构建的能量世界中能量盒子数量
    public static final int BOX_AMOUNT = 100;
    //每个盒子初始能量
    public static final double INITIAL_ENERGY = 1000;

    public static void main(String[] args) {
        EnergySystemFirst eng = new EnergySystemFirst(BOX_AMOUNT, INITIAL_ENERGY);
        for (int i = 0; i < BOX_AMOUNT; i++) {
            EnergyTransferTtk task = new EnergyTransferTtk(eng, i, INITIAL_ENERGY);
            Thread t = new Thread(task, "TransferThread_" + i);
            t.start();
        }
    }


    /**
     * 返回能量盒子的长度
     */
    public int getBoxAmount() {
        return energyBoxes.length;
    }

}


class EnergyTransferTtk implements Runnable {

    //共享的能量世界
    private EnergySystemFirst energySystem;
    //能量转移的源能量盒子下标
    private int fromBox;
    //单次能量转移最大单元
    private double maxAmount;
    //最大休眠时间（毫秒）
    private int DELAY = 1000;

    public EnergyTransferTtk(EnergySystemFirst energySystem, int from, double max) {
        this.energySystem = energySystem;
        this.fromBox = from;
        this.maxAmount = max;
    }

    public void run() {
        try {
            while (true) {
                int toBox = (int) (energySystem.getBoxAmount() * Math.random());
                double amount = maxAmount * Math.random();
                energySystem.transfer(fromBox, toBox, amount);
//                Thread.sleep((int) (DELAY * Math.random()));
                Thread.sleep(DELAY);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}